﻿using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Abp.Authorization.Users;
using Abp.Extensions;
using Abp.Timing;
using Abp.UI;
using ARchGL.Platform.Authorization.Roles;

namespace ARchGL.Platform.Authorization.Users
{
    /// <summary>
    /// Represents a user in the system.
    /// </summary>
    public class User : AbpUser<User>
    {
        public virtual Guid? ProfilePictureId { get; set; }

        public virtual bool ShouldChangePasswordOnNextLogin { get; set; }

        public DateTime? SignInTokenExpireTimeUtc { get; set; }

        public string SignInToken { get; set; }

        public string GoogleAuthenticatorKey { get; set; }

        //Can add application specific user properties here

        /// <summary>
        /// 用户 GUID 标识
        /// </summary>
        public Guid PrimaryId { get; set; }
        /// <summary>
        /// 用户类型
        /// </summary>
        public UserType Type { get; set; }
        /// <summary>
        /// 性别：1男、2女
        /// </summary>
        public int Gender { get; set; }
        /// <summary>
        /// 头像
        /// </summary>
        [MaxLength(200)]
        public string Avatar { get; set; }
        /// <summary>
        /// 职位信息
        /// </summary>
        [MaxLength(50)]
        public string Position { get; set; }

        /// <summary>
        /// 角色名称
        /// </summary>
        [NotMapped]
        public string RoleName { get; set; }

        /// <summary>
        /// 角色编码
        /// </summary>
        [NotMapped]
        public string RoleCode { get; set; }

        public User()
        {
            IsLockoutEnabled = true;
            IsTwoFactorEnabled = true;
        }

        /// <summary>
        /// Creates admin <see cref="User"/> for a tenant.
        /// </summary>
        /// <param name="tenantId">Tenant Id</param>
        /// <param name="emailAddress">Email address</param>
        /// <returns>Created <see cref="User"/> object</returns>
        public static User CreateTenantAdminUser(int tenantId, string emailAddress)
        {
            var user = new User
            {
                TenantId = tenantId,
                UserName = AdminUserName,
                Name = AdminUserName,
                Surname = AdminUserName,
                EmailAddress = emailAddress
            };

            user.SetNormalizedNames();

            return user;
        }

        /// <summary>
        /// 创建租户中的普通 <see cref="User"/> 用户
        /// </summary>
        /// <param name="tenantId"></param>
        /// <param name="userName"></param>
        /// <param name="name"></param>
        /// <param name="emailAddress"></param>
        /// <returns></returns>
        public static User CreateTenantNormalUser(int tenantId, string userName, string name, string emailAddress)
        {
            var user = new User
            {
                TenantId = tenantId,
                UserName = userName,
                Name = name,
                Surname = userName,
                EmailAddress = emailAddress
            };
            user.SetNormalizedNames();
            return user;
        }

        public static string CreateRandomPassword()
        {
            return Guid.NewGuid().ToString("N").Truncate(16);
        }

        public override void SetNewPasswordResetCode()
        {
            /* This reset code is intentionally kept short.
             * 重置验证码需要保持简短。
             * It should be short and easy to enter in a mobile application, where user can not click a link.
             * 它必须是简短且容易在移动设备上输入，当用户不能点击链接时。
             */
            PasswordResetCode = Guid.NewGuid().ToString("N").Truncate(10).ToUpperInvariant();
        }

        public void Unlock()
        {
            AccessFailedCount = 0;
            LockoutEndDateUtc = null;
        }

        public void SetSignInToken()
        {
            SignInToken = Guid.NewGuid().ToString();
            SignInTokenExpireTimeUtc = Clock.Now.AddMinutes(1).ToUniversalTime();
        }

        /// <summary>
        /// 检查用户类型，特定用户不能直接修改信息
        /// 接口租户不能被重置密码，如果需要可以手动调试获取密码再修改数据库
        /// </summary>
        public void CheckType()
        {
            if (Type == UserType.接口租户)
                throw new UserFriendlyException("您的请求无效", "当前用户没有权限操作");
        }

        /// <summary>设置角色信息</summary>
        public void SetRoleInfo(Role role)
        {
            RoleCode = role?.Name;
            RoleName = role?.DisplayName;
        }
    }
}